/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_components/zhiqim_manager.htm
 *
 * Zhiqim Manager is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.manager;

import java.util.ArrayList;
import java.util.List;

import org.zhiqim.httpd.HttpContext;
import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.HttpSessionUser;
import org.zhiqim.httpd.context.ZmlContexts;
import org.zhiqim.kernel.annotation.AnAlias;
import org.zhiqim.kernel.annotation.AnGenerics;
import org.zhiqim.kernel.json.Jsons;
import org.zhiqim.kernel.util.Validates;
import org.zhiqim.manager.dbo.ZmrMenu;
import org.zhiqim.manager.dbo.ZmrOperator;

/**
 * 操作员会话用户信息
 *
 * @version v1.0.0 @author zouzhigang 2015-5-28 新建与整理
 */
@AnAlias("ZmrSessionUser")
public class ZmrSessionUser extends HttpSessionUser implements ZmrConstants
{
    private ZmrOperator operator;
    
    @AnGenerics(ZmrMenu.class)
    private List<ZmrMenu> menuList;
    private String topFirstMenuCode;
    private String menuUrlRules;
    private String mainUrl;
    private String welcomeUrl;
    private boolean sidebar = true;
    
    public ZmrSessionUser()
    {
        this.menuList = new ArrayList<ZmrMenu>();
    }
    
    /**********************************************************************************************/
    //初始创建，用于登录绑定前操作，使用init开头的方法，无需刷新到可能的共享会话
    /**********************************************************************************************/
    
    public ZmrSessionUser initOperator(ZmrOperator operator)
    {
        this.operator = operator;
        return this;
    }
    
    public ZmrSessionUser initMenuList(HttpContext context, List<ZmrMenu> menuList) throws Exception
    {
        if (menuList == null || menuList.isEmpty())
            return this;

        this.menuList = menuList;
        StringBuffer strb = new StringBuffer();
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getMenuUrl() != null)
            {//ROOT是null
                menu.setMenuUrl(ZmlContexts.parseZmlContent(context, menu.getMenuUrl()));
                strb.append(menu.getMenuUrl()).append(",");
            }
        }
        
        menuUrlRules = strb.toString();
        
        //取顶级第一个栏目
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getMenuType() == 1 && menu.getMenuLevel() == 1)
            {
                topFirstMenuCode = menu.getMenuCode();
                break;
            }
        }
        
        return this;
    }
    
    public ZmrSessionUser initWelcomeUrl(String welcomeUrl)
    {
        this.welcomeUrl = welcomeUrl;
        return this;
    }
    
    public ZmrSessionUser initMainUrl(String mainUrl)
    {
        this.mainUrl = mainUrl;
        return this;
    }
    
    /**********************************************************************************************/
    //中途设置，setOperator/setMenuList/setMainUrl/setSidebar，需要flush
    /**********************************************************************************************/
    
    /** 修改个人信息变化 */
    public void setOperator(ZmrOperator operator)
    {
        initOperator(operator).flush();
    }
    
    /** 修改菜单时权限变化 */
    public void setMenuList(HttpContext context, List<ZmrMenu> menuList) throws Exception
    {
        initMenuList(context, menuList).flush();
    }
    
    /** 由页面AJAX设置 */
    public void setMainUrl(String mainUrl)
    {
        this.mainUrl = mainUrl;
        this.flush();
    }
    
    /** 由页面AJAX设置 */
    public void setSidebar(boolean sidebar)
    {
        this.sidebar = sidebar;
        this.flush();
    }
    
    /***************************************************************************************/
    //基础相关信息
    /***************************************************************************************/
    
    public String getSessionName()
    {
        return operator.getOperatorCode();
    }
    
    public String getRootPath(String path)
    {
        return getContext().getRootPath(path);
    }
    
    /***************************************************************************************/
    //操作员相关信息
    /***************************************************************************************/
    
    public ZmrOperator getOperator()
    {
        return operator;
    }

    public String getOperatorCode()
    {
        return operator.getOperatorCode();
    }

    public String getOperatorName()
    {
        return operator.getOperatorName();
    }
    
    public String getOperatorPassSalt()
    {
        return operator.getOperatorPassSalt();
    }

    public int getOperatorType()
    {
        return operator.getOperatorType();
    }
    
    public int getOperatorTypeThenG()
    {
        return isSuperAdmin()?0:1;
    }
    
    public boolean isSuperAdmin()
    {
        return getOperatorType() == 0;
    }
    
    public boolean isAdmin()
    {
        return operator.getOperatorType() == 0 || operator.getOperatorType() == 1;
    }
    
    public String getOperatorMobile()
    {
        return operator.getOperatorMobile();
    }

    public String getOperatorEmail()
    {
        return operator.getOperatorEmail();
    }

    /***************************************************************************************/
    //操作员参数相关信息
    /***************************************************************************************/
    
    public boolean hasOperatorParam(String key)
    {
        if (Validates.isEmptyBlank(operator.getOperatorParam()))
            return false;
        
        return Jsons.getString(operator.getOperatorParam(), key) != null;
    }
    
    public String getOperatorParam(String key)
    {
        if (Validates.isEmptyBlank(operator.getOperatorParam()))
            return null;
        
        return Jsons.getString(operator.getOperatorParam(), key);
    }
    
    public int getOperatorParamInt(String key)
    {
        if (Validates.isEmptyBlank(operator.getOperatorParam()))
            return -1;
        
        return Jsons.getInt(operator.getOperatorParam(), key);
    }
    
    public long getOperatorParamLong(String key)
    {
        if (Validates.isEmptyBlank(operator.getOperatorParam()))
            return -1;
        
        return Jsons.getLong(operator.getOperatorParam(), key);
    }
    
    /***************************************************************************************/
    //操作员权限相关信息
    /***************************************************************************************/
    
    public List<ZmrMenu> getMenuList()
    {
        return menuList;
    }

    public boolean hasMenuRule(String path)
    {
        if (path == null)
            return false;

        return menuUrlRules.indexOf(path) != -1;
    }
    
    /** 获取顶级栏目 */
    public List<ZmrMenu> getTopMenuList()
    {
        List<ZmrMenu> list = new ArrayList<>();
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getMenuLevel() == 1 && menu.getMenuType() == 1)
                list.add(menu);
        }
        
        return list;
    }
    
    /** 获取顶级栏目 */
    public ZmrMenu getTopMenuFirst()
    {
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getMenuLevel() == 1 && menu.getMenuType() == 1)
                return menu;
        }
        
        return null;
    }
    
    /** 判断存在子菜单 */
    public boolean hasChildMenu(String menuCode)
    {
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getParentCode().equals(menuCode) && menu.getMenuType() == 1)
                return true;
        }
        
        return false;
    }
    
    /** 获取第一个子菜单 */
    public ZmrMenu getChildMenuFirst(String menuCode)
    {
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getParentCode().equals(menuCode) && menu.getMenuType() == 1)
                return menu;
        }
        
        return null;
    }
    
    /** 获取子菜单列表 */
    public List<ZmrMenu> getChildMenuList(String menuCode)
    {
        List<ZmrMenu> list = new ArrayList<>();
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getParentCode().equals(menuCode) && menu.getMenuType() == 1)
                list.add(menu);
        }
        
        return list;
    }
    
    /** 通过子菜单获取顶级菜单 */
    public ZmrMenu getTopMenuByChild(String childMenuCode)
    {
        if (childMenuCode == null)
            return null;
        
        ZmrMenu child = null;
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menu.getMenuCode().equals(childMenuCode))
            {
                if (menu.getMenuType() != 1 && menu.getMenuLevel() != 1)
                    return null;//不是二级菜单，暂时不支持
                
                child = menu;
                break;
            }
        }
        
        return (child == null)?null:getMenu(child.getParentCode());
    }
    
    /**
     * 获取选中的顶级菜单，允许页面指定，未指定取当前mainUrl进行比较，如果未找到返回null
     * 
     * @param designatedPath    指定的路径
     * @return                  选中的菜单
     */
    public String getSelectedTopMenuCodeByMainUrl(String designatedPath)
    {
        return getSelectedTopMenuCode(mainUrl, designatedPath, null);
    }
    
    /**
     * 获取选中的顶级菜单，允许页面指定，未指定取当前path进行比较，如果未找到则取第一个顶级菜单
     * 
     * @param request           请求
     * @param designatedPath    指定的路径
     * @return                  选中的菜单
     */
    public String getSelectedTopMenuCodeOrFirstMenuCode(HttpRequest request, String designatedPath)
    {
        return getSelectedTopMenuCode(request.getPathInContext(), designatedPath, topFirstMenuCode);
    }
    
    /**
     * 获取选中的顶级菜单，允许页面指定，未指定取当前path进行比较，如果未找到取缺省值
     * 
     * @param request           请求
     * @param designatedPath    指定的路径
     * @param defaultMenuCode   缺省菜单
     * @return                  选中的菜单
     */
    public String getSelectedTopMenuCode(HttpRequest request, String designatedPath)
    {
        return getSelectedTopMenuCode(request.getPathInContext(), designatedPath, null);
    }
    
    /**
     * 获取选中的顶级菜单，允许页面指定，未指定取当前path进行比较，如果未找到取缺省值
     * 
     * @param requestPath       请求路径
     * @param designatedPath    指定的路径
     * @param defaultMenuCode   缺省菜单
     * @return                  选中的菜单
     */
    public String getSelectedTopMenuCode(String requestPath, String designatedPath, String defaultMenuCode)
    {
        String path = (designatedPath == null)?requestPath:designatedPath;
        ZmrMenu menu = getMenuByPath(path);
        if (menu == null || menu.getMenuLevel() == 0)
            return defaultMenuCode;
        
        if (menu.getMenuLevel() == 1)
        {//顶级
            return menu.getMenuType() == 1?menu.getMenuCode():defaultMenuCode;
        }
     
        while(true)
        {//大于顶级循环找到顶级为止
            menu = getMenu(menu.getParentCode());
            if (menu == null)
                return null;
            
            if (menu.getMenuLevel() > 1)
                continue;
            
            return menu.getMenuType() == 1?menu.getMenuCode():defaultMenuCode;
        }
    }
    
    /**
     * 获取选中的顶级菜单，允许页面指定，未指定取当前path进行比较，如果未找到则取第一个顶级菜单
     * 
     * @param request           请求
     * @param designatedPath    指定的path
     * @return
     */
    public String getSelectedSecondMenuCode(HttpRequest request, String designatedPath)
    {
        String path = (designatedPath == null)?request.getPathInContext():designatedPath;
        ZmrMenu menu = getMenuByPath(path);
        if (menu == null || menu.getMenuLevel() <= 1)
            return null;
        
        if (menu.getMenuLevel() == 2)
        {//二级
            return menu.getMenuType() == 1?menu.getMenuCode():null;
        }
     
        while(true)
        {//大于二级循环找到二级为止
            menu = getMenu(menu.getParentCode());
            if (menu == null)
                return null;
            
            if (menu.getMenuLevel() > 2)
                continue;
            
            return menu.getMenuType() == 1?menu.getMenuCode():null;
        }
    }
    
    public ZmrMenu getMenu(String menuCode)
    {
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (menuCode.equals(menu.getMenuCode()))
                return menu;
        }
        
        return null;
    }
    
    /** 通过路径找到菜单，级别大的优先 */
    public ZmrMenu getMenuByPath(String path)
    {
        int ind = path.indexOf("?");
        if (ind != -1)
            path = path.substring(0, ind);
        
        ZmrMenu selected = null;
        for (ZmrMenu menu : menuList)
        {
            if (menu.getMenuStatus() != 0)
                continue;
            
            if (Validates.isNotEmpty(menu.getMenuUrl()) && menu.getMenuUrl().contains(path))
            {
                if (selected == null || selected.getMenuLevel() < menu.getMenuLevel())
                    selected = menu;
            }
        }
        
        return selected;
    }
    
    /**************************************************************************************/
    //框架时左右相关信息
    /**************************************************************************************/
    
    public String getMainUrl()
    {
        return mainUrl;
    }
    
    public boolean isWelcomeUrl()
    {
        return Validates.isEqual(welcomeUrl, mainUrl);
    }

    public boolean hasSidebar()
    {
        return sidebar;
    }

    public String getSidebarClass()
    {
        return sidebar?"":"z-hide";
    }

    /**************************************************************************************/
    //头像相关信息
    /**************************************************************************************/
    
    public String getAvatar50()
    {
        return operator.getOperatorAvatar()==0?getRootPath(_PATH_SERVICE_RES_AVATAR_):getAvatarUrl(getOperatorAvatar(), 50);
    }

    public String getAvatar100()
    {
        return operator.getOperatorAvatar()==0?getRootPath(_PATH_SERVICE_RES_AVATAR_):getAvatarUrl(getOperatorAvatar(), 100);
    }
    
    public String getAvatar150()
    {
        return operator.getOperatorAvatar()==0?getRootPath(_PATH_SERVICE_RES_AVATAR_):getAvatarUrl(getOperatorAvatar(), 150);
    }
    
    public long getOperatorAvatar()
    {
        return operator.getOperatorAvatar();
    }
    
    public String getAvatarUrl(long avatarId, int avatarSize)
    {
        return getRootPath(new StringBuffer("/").append(getContext().getAttribute(ZMR_PATH)).append("/avatar/").append(avatarId).append("/").append(avatarSize).append(".png").toString());
    }
    
    /**************************************************************************************/
    //会话默认选中
    /**************************************************************************************/
    
    public long getSelectedDeptId(long defaultValue)
    {
        return getValueLong(ZMR_SESSION_USER_DEPT_ID, defaultValue);
    }
    
    public long getSelectedRoleId(long defaultValue)
    {
        return getValueLong(ZMR_SESSION_USER_ROLE_ID, defaultValue);
    }
}
